Управління записами
===================

Під управлінням записами мається на увазі відображення їх списку у адміністративному
розділі з можливістю переглядати записи з будь-яким статусом, редагувати та
видаляти їх. Ця функціональність реалізується у діях `admin` та `delete`
відповідно. Код, згенерований за допомогою `Gii`, майже не потребує
змін. Нижче ми пояснимо, як реалізовані ці дії.

Відображення записів у вигляді таблиці
--------------------------------------

Дія `admin` виводить записи із всіма статусами у вигляді таблиці,
розбитої на кілька сторінок, яка підтримує сортування по декільком колонкам.
Далі наведено метод `actionAdmin()` контролера `PostController`:

~~~
[php]
public function actionAdmin()
{
	$model=new Post('search');
	if(isset($_GET['Post']))
		$model->attributes=$_GET['Post'];
	$this->render('admin',array(
		'model'=>$model,
	));
}
~~~

Даний код повністю згенеровано `Gii`. 
Спочатку створюється модель `Post` із сценарієм `search` 
[scenario](/doc/guide/uk/form.model), який ми будемо використовувати для
збору критеріїв пошуку, вказаних користувачем. 
Далі ми присвоюємо дані, введені користувачем, моделі. 
І, нарешті, ми виводимо відображення `admin`, використовуючи модель.

Нижче приведений код відображення `admin`:

~~~
[php]
<?php
$this->breadcrumbs=array(
	'Manage Posts',
);
?>
<h1>Manage Posts</h1>

<?php $this->widget('zii.widgets.grid.CGridView', array(
	'dataProvider'=>$model->search(),
	'filter'=>$model,
	'columns'=>array(
		array(
			'name'=>'title',
			'type'=>'raw',
			'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)'
		),
		array(
			'name'=>'status',
			'value'=>'Lookup::item("PostStatus",$data->status)',
			'filter'=>Lookup::items('PostStatus'),
		),
		array(
			'name'=>'create_time',
			'type'=>'datetime',
			'filter'=>false,
		),
		array(
			'class'=>'CButtonColumn',
		),
	),
)); ?>
~~~

Для виведення записів ми використовуємо компонент [CGridView], який
розбиває дані на сторінки і дозволяє сортувати їх по стовпцях.
Наша зміна стосується, головним чином, відображення кожного стовпця.
Наприклад, для стовпця `title` ми вказуємо, що він повинен містити
посилання на перегляд запису. Вираз `$data->url` повертає значення
властивості `url`, яке ми визначаємо у класі `Post`.

> Tip|Підказка: При виведенні тексту ми використовуємо [CHtml::encode()] для
  кодування сутностей HTML. Це дозволяє уникнути атак через [міжсайтовий
  скриптинг](/doc/guide/uk/topics.security).


Видалення записів
-----------------

У таблиці данних `admin` у кожному рядку є кнопка «Видалити», яка
видаляє відповідний запис. Дія `delete` виглядає наступним чином:

~~~
[php]
public function actionDelete()
{
	if(Yii::app()->request->isPostRequest)
	{
		// we only allow deletion via POST request
		$this->loadModel()->delete();

		if(!isset($_GET['ajax']))
			$this->redirect(array('index'));
	}
	else
		throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
~~~

Наведений вище код повністю згенеровано `Gii`. 
Зупинимося докладніше на перевірці `$_GET['ajax']`. 
У віджеті [CGridView] сортування, розбивка на сторінки 
та видалення за замовчуванням реалізовані з використанням AJAX. 
Тобто при виконанні перерахованих дій сторінка перезавантажуватися не буде.
Віджет може працювати і без AJAX (якщо властивість `ajaxUpdate` виставлено у
`false` або відключений JavaScript). У дії `delete` при AJAX запиті перенаправлення
проводитися не повинно.

Видалення запису повинно викликати видалення всіх коментарів до неї. 
До того ж, ми повинні оновити теги у таблиці `tbl_tag`. 
Обидва завдання можуть бути виконані у методі `afterDelete` моделі `Post`:

~~~
[php]
protected function afterDelete()
{
	parent::afterDelete();
	Comment::model()->deleteAll('post_id='.$this->id);
	Tag::model()->updateFrequency($this->tags, '');
}
~~~

Код, наведений вище не складний: спочатку видаляються всі коментарі, чий
`post_id` дорівнює ID запису, що видаляється. Далі оновлюється таблиця `tbl_tag`.

> Tip|Підказка: Ми видаляємо коментарі запису, що видаляється, у коді, так як SQLite
не підтримує обмеження по зовнішньому ключу. У СУБД, які дані обмеження
підтримують (наприклад, MySQL або PostgreSQL), можна використовувати каскадне
видалення коментарів у разі видалення запису. У цьому випадку немає необхідності
видаляти коментарі у коді.
